/**
 * @description:   foo1 函数在调用时，仍然会使用定义时所在的作用域中的变量。
 */
/*
var n = 100
function foo1() {
    console.log("🚀 ~ foo1 ~ n:", n)
}
function foo2() {
    var n = 200
    console.log("🚀 ~ foo2 ~ n:", n)
    foo1()
}
foo2()
console.log("🚀 ~ n:", n)
 */

/**
 * @description: 等同
 * function foo() {
    var a; // a 被提升到函数作用域的顶部，此时值为 undefined
    console.log("🚀 ~ foo ~ a:", a); // 这里会打印 undefined
    return; // 函数在此处返回，下面的代码不会执行
    a = 200; // 这行代码永远不会执行
}
 */

/* var a = 100
function foo() {
    console.log("🚀 ~ foo ~ a:", a)
    return
    var a = 200
}
foo()
 */

/**
 * @description: 打印函数在自己的函数作用域里面没有找到a就跑到外层作用域里面去找
 */
/*
class c1 {
    data = []
    setValue(v) {
        this.data.push(v)
    }
    showData() {
        this.data.forEach(item => {
            item()
        })
    }
}
const c = new c1()
var a = 1
function f1() {
    c.setValue(function () {
        console.log(a);
    })
    var a = 2
}
f1()
c.showData()
 */
/**
 * @description: 关键点是 f1 函数内部的 this 指向。
 * 由于 showData 方法中使用的是箭头函数来遍历 data 数组（即 this.data.forEach((item) => { ... })），
 * 箭头函数中的 this 继承自 showData 方法的上下文，也就是 Person 类的实例 p。
    然而，f1 是一个普通函数，它的 this 指向取决于它的调用方式。
    在 showData 方法中，f1 是直接调用的（item()），
    所以 f1 中的 this 默认会是 undefined（在严格模式下）。
    如果没有启用严格模式，this 会指向全局对象（在浏览器中是 window）。
 */
/*
class Person {
    data = []
    setData(v) {
        this.data.push(v)
    }
    showData() {
        this.data.forEach((item) => {
            item()
        })
    }
}

const p = new Person()
function f1() {
    console.log(this);
}
p.setData(f1)
p.showData()
 */

/**
 * @description: sss() 是以函数的形式独立调用的，所以 this 指向全局对象 window
 *
 */
/*
var name = "window";

var person = {
    name: "person",
    sayName: function () {
        console.log(this.name);
    }
};

function sayName() {
    var sss = person.sayName;
    sss();
    person.sayName();  // 隐式绑定: person
    (person.sayName)(); // 隐式绑定: person
    (b = person.sayName)(); // 独立调用: window
}

sayName();

 */

/* var name = "window";

var person = {
    name: "person",
    sayName: function () {
        console.log(this.name);
    }
};

function sayName() {
    var sss = person.sayName;
    sss();
    person.sayName();
    (person.sayName)();
    (b = person.sayName)();
}

sayName(); */

// 独立调用: window
// 隐式绑定: person
// 隐式绑定: person
// 独立调用: window

/**
 * @description: 
 * 
 */

/* 
var name = 'window'

var person1 = {
    name: 'person1',
    foo1: function () {
        console.log(this.name)
    },
    foo2: () => console.log(this.name),
    foo3: function () {
        return function () {
            console.log(this.name)
        }
    },
    foo4: function () {
        return () => {
            console.log(this.name)
        }
    }
}

var person2 = { name: 'person2' }

person1.foo1(); // 隐式绑定: person1
person1.foo1.call(person2); // 显式绑定: person2

person1.foo2(); // 箭头函数不绑定this, 去外层作用域找: window
person1.foo2.call(person2);  // 箭头函数不绑定this, 去外层作用域找: window

person1.foo3()(); // 独立调用: window
person1.foo3.call(person2)(); // 独立调用: window
person1.foo3().call(person2); // 显式绑定: person2

person1.foo4()(); // 箭头函数找外层作用域的this, 外层作用域的this是隐式绑定: person1
person1.foo4.call(person2)(); // 箭头函数找外层作用域的this, 外层作用域的this是显式绑定: person2
person1.foo4().call(person2); // 箭头函数找外层作用域的this, 外层作用域的this是隐式绑定: person1
 */
/**
 * @description: 
 */
/* 
var name = 'window'

function Person(name) {
    this.name = name
    this.foo1 = function () {
        console.log(this.name)
    },
        this.foo2 = () => console.log(this.name),
        this.foo3 = function () {
            return function () {
                console.log(this.name)
            }
        },
        this.foo4 = function () {
            return () => {
                console.log(this.name)
            }
        }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.foo1() // 隐式绑定: person1
person1.foo1.call(person2) // 显式绑定: person2

person1.foo2() // 箭头函数不绑定this, 外层作用域是new绑定: person1
person1.foo2.call(person2) // 箭头函数不绑定this, 外层作用域是new绑定: person1

person1.foo3()() // 独立调用: window
person1.foo3.call(person2)() // 独立调用: window
person1.foo3().call(person2) // 显式绑定: person2

person1.foo4()() // 箭头函数不绑定this, 外层作用域是隐式绑定: person1
person1.foo4.call(person2)() // 箭头函数不绑定this, 外层作用域是显式绑定: person2
person1.foo4().call(person2) // 箭头函数不绑定this, 外层作用域是隐式绑定: person1
 */
/* var name = 'window'

function Person(name) {
    this.name = name
    this.obj = {
        name: 'obj',
        foo1: function () {
            return function () {
                console.log(this.name)
            }
        },
        foo2: function () {
            return () => {
                console.log(this.name)
            }
        }
    }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()()
person1.obj.foo1.call(person2)()
person1.obj.foo1().call(person2)

person1.obj.foo2()()
person1.obj.foo2.call(person2)()
person1.obj.foo2().call(person2)  */